package com.mdb.open.epay.facade.epay;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.StrUtil;
import com.mdb.bc.api.data.ResultEx;
import com.mdb.bc.utils.DateTimeUtil;
import com.mdb.bc.utils.ObjectUtil;
import com.mdb.open.common.enums.ProductCodeEnum;
import com.mdb.open.epay.cache.SignOtpBean;
import com.mdb.open.epay.config.CoreConfig;
import com.mdb.open.epay.config.EPayOpenProperties;
import com.mdb.open.epay.domain.bo.SendSignOtpBo;
import com.mdb.open.epay.domain.bo.SignBo;
import com.mdb.open.epay.domain.bo.UnsignBo;
import com.mdb.open.epay.domain.po.customer.CustBaseInfo;
import com.mdb.open.epay.domain.po.epay.*;
import com.mdb.open.epay.domain.po.product.Product;
import com.mdb.open.epay.domain.vo.epay.SignVo;
import com.mdb.open.epay.domain.vo.epay.UnsignVo;
import com.mdb.open.epay.enums.constant.CoreAccCtrlEnum;
import com.mdb.open.epay.enums.constant.CoreCustTypeEnum;
import com.mdb.open.epay.enums.constant.SMSEnum;
import com.mdb.open.epay.enums.status.QpSignSerialStatusEnum;
import com.mdb.open.epay.enums.status.QpSignStatusEnum;
import com.mdb.open.epay.enums.status.QpUserOpenStatusEnum;
import com.mdb.open.epay.enums.status.QuotaLimitStatusEnum;
import com.mdb.open.epay.enums.type.*;
import com.mdb.open.epay.service.customer.CustBaseInfoService;
import com.mdb.open.epay.service.epay.*;
import com.mdb.open.epay.service.epay.biz.bo.SignBizBo;
import com.mdb.open.epay.service.epay.biz.bo.UnsignBizBo;
import com.mdb.open.epay.service.epay.biz.service.SignBizService;
import com.mdb.open.epay.service.epay.handle.CoreSMSHandler;
import com.mdb.open.epay.service.epay.handle.QueryCoreHandle;
import com.mdb.open.epay.service.epay.handle.dto.GetCoreAccountDto;
import com.mdb.open.epay.service.epay.handle.dto.GetCoreCustDto;
import com.mdb.open.epay.service.epay.handle.dto.SendCoreSMSDto;
import com.mdb.open.epay.service.epay.handle.vo.CoreAccountVo;
import com.mdb.open.epay.service.epay.handle.vo.CoreCustVo;
import com.mdb.open.epay.service.product.ProductService;
import com.mdb.open.epay.utils.NoGenUtil;
import com.mdb.open.epay.validator.OtpValidator;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 签约相关
 *
 * @author liuyi
 * @date 2019/11/14
 **/
@Log4j2
@Service
public class SignFacade {

    @Autowired
    private QpSignService qpSignService;

    @Autowired
    private QpSignSerialService qpSignSerialService;

    @Autowired
    private QpUserOpenService qpUserOpenService;

    @Autowired
    private QpCustConfigService qpCustConfigService;

    @Autowired
    private EpQuotaLimitService epQuotaLimitService;

    @Autowired
    private OtpValidator otpValidator;

    @Autowired
    private ProductService productService;

    @Autowired
    private CustBaseInfoService custBaseInfoService;

    @Autowired
    private EPayOpenProperties ePayOpenProperties;

    @Autowired
    private SignBizService signBizService;

    @Autowired
    private QueryCoreHandle queryCoreHandle;

    @Autowired
    private CoreSMSHandler coreSMSHandler;

    /**
     * 發送簽約短信
     */
    public ResultEx sendSignOtp(SendSignOtpBo bo) {
        //1、账户是否开通快捷产品  查询qp_user_open
        QpUserOpen existQpUserOpen = qpUserOpenService.get(bo.getCustomerCode(), ProductCodeEnum.EP_QP.getValue(), bo.getBankCardNo());
        if (ObjectUtil.isNotEmpty(existQpUserOpen)) {
            //曾经开通过 检查开通状态
            if (!QpUserOpenStatusEnum.OPENED.getValue().equals(existQpUserOpen.getStatus())) {
                return ResultEx.fail("用戶賬戶快捷支付開通狀態異常");//TODO
            }
        }
        //2、是否已签  查询qp_sign
        QpSign qpSign = qpSignService.get(bo.getCustomerCode(), bo.getBankCardNo());
        if (ObjectUtil.isNotEmpty(qpSign) && QpSignStatusEnum.SIGNED.getValue().equals(qpSign.getStatus())) {
            //已签约
            return ResultEx.fail("已簽約，禁止重複簽約");//TODO
        }

        //3、同一用户(核心同一客户)可签账户数校验 qp_cust_config
        QpCustConfig qpCustConfig = qpCustConfigService.get(bo.getCustomerCode());
        if (ObjectUtil.isEmpty(qpCustConfig)) {
            return ResultEx.fail("客戶配置缺失");//TODO
        }
        Integer signCountMax = qpCustConfig.getSignCountMax();

        //4、查询核心验证签约身份信息要素(银行预留手机号，证件类型，证件号码,卡类型）  查询核心接口

        GetCoreCustDto getCoreCustDto = new GetCoreCustDto();
        getCoreCustDto.setIdTyp(bo.getCertType());
        getCoreCustDto.setIdNo(bo.getCertNo());
        getCoreCustDto.setType(CoreConfig.CUST_TYPE_H);
        log.info("調用核心，查詢客戶信息");
        ResultEx<CoreCustVo> resultEx = queryCoreHandle.getCoreCust(getCoreCustDto);
        if (resultEx.isFailed()) {
            return ResultEx.fail("客戶信息查詢失敗");//TODO 客戶信息查詢失敗
        }
        CoreCustVo coreCustVo = resultEx.getData();
        //查询核心接口，获取客户号，根据客户号查询签约表
        String coreClientNo = coreCustVo.getCiNo();
        String engName = coreCustVo.getEngName();
        String chnName = coreCustVo.getChnName();

        if (ePayOpenProperties.isPhoneCheck()) {
            //  4.1证件类型，证件号查询客户号及预留手机号，手机少是否一致 TODO 手机号区域 +86  86
            if (!bo.getPhoneArea().equals(coreCustVo.getEaddrMobCntyno())
                    || !bo.getPhoneNo().equals(coreCustVo.getEaddrMobNo())) {
                return ResultEx.fail("預留手機號不一致");//TODO 預留手機號不一致
            }
        } else {
            log.error("未檢校驗留手機號是否一致，請配置");
        }

        //核心客户类型校验
        if (!CoreCustTypeEnum.P.getValue().equals(coreCustVo.getCustType())) {
            return ResultEx.fail("客戶類型不支持，暫只允許個人用戶！");//TODO 客戶類型不支持，暫只允許個人用戶！
        }

        Integer count = qpSignService.countByStatus(bo.getCustomerCode(), coreClientNo, QpSignStatusEnum.SIGNED.getValue());
        if (count >= signCountMax) {
            return ResultEx.fail("超過最大簽約數，禁止繼續簽約");//TODO
        }

        //  4.2客户号查询账号信息，账号类型及币种验证(是否活期賬戶&&是否MOP幣種)
        GetCoreAccountDto getCoreAccountDto = new GetCoreAccountDto();
        getCoreAccountDto.setCiNo(coreClientNo);
        getCoreAccountDto.setCtl1(CoreAccCtrlEnum.SAME_ACCOUNT_ONLY.getValue());
        getCoreAccountDto.setCtl2(BankAccTypeEnum.CURRENT.getCoreAccType());
        log.info("调用核心，签约信息验证");
        ResultEx<CoreAccountVo> resultCoreAccount = queryCoreHandle.getCoreAccount(getCoreAccountDto);
        if (resultCoreAccount.isFailed()) {
            return ResultEx.fail("無法獲取賬戶信息");//TODO 無法獲取賬戶信息
        }
        CoreAccountVo coreAccountVo = resultCoreAccount.getData();
        if (coreAccountVo.getLists().isEmpty()) {
            return ResultEx.fail("獲取賬戶信息為空");//TODO 獲取賬戶信息為空
        }
        boolean hasCurrentMOPAccount = coreAccountVo.getLists().stream()
                .anyMatch(account ->
                        bo.getBankCardNo().equals(account.getQactAc())
                                && BankAccTypeEnum.CURRENT.getCoreAccType().equals(account.getQactCtl3())
                                && CcyTypeEnum.MOP.getValue().equals(account.getQactCcy()));
        if (!hasCurrentMOPAccount) {
            return ResultEx.fail("用戶信息校驗失敗");//TODO 沒有活期賬戶
        }
        //5、發送Otp驗證碼 证件号，证件类型，手机号+账号：（驗證碼，核心客户号） 缓存用于验证
        //生成otp验证码
        String otpCode = NoGenUtil.genRandomOtpCode();
        LocalDateTime now = LocalDateTime.now();
        if (ePayOpenProperties.isOtpCheck()) {
            log.info("簽約调用核心短信发送！");
            String bankAccountNo = bo.getBankCardNo();
            String accountNo = StrUtil.sub(bankAccountNo, bankAccountNo.length() - 4, bankAccountNo.length());
            SendCoreSMSDto sendCoreSMSDto = new SendCoreSMSDto();
            sendCoreSMSDto.setSmsTemplateId(CoreConfig.SMS_TEMPLATE_SIGNOPT);
            sendCoreSMSDto.setTransactionType(SMSEnum.TRANS_TYPE_TEMPLATE.getValue());
            sendCoreSMSDto.setTransactionName(CoreConfig.TRANS_NAME_SIGN);
            sendCoreSMSDto.setSendType(SMSEnum.SEND_TYPE_SMS.getValue());
            sendCoreSMSDto.setSmsAccountNo(accountNo);
            sendCoreSMSDto.setOpt(otpCode);
            sendCoreSMSDto.setPhoneNo(bo.getPhoneArea() + bo.getPhoneNo());
            sendCoreSMSDto.setDate(DateTimeUtil.convert2Str(now, ePayOpenProperties.getSmsDatePatter()));
            sendCoreSMSDto.setTime(DateTimeUtil.convert2Str(now, ePayOpenProperties.getSmsTimePatter()));
            sendCoreSMSDto.setMessageLength("480");
            sendCoreSMSDto.setFiller(" ");
            sendCoreSMSDto.setSendDate("00000000");
            sendCoreSMSDto.setSendTime("000000");

            ResultEx smsResultEx = coreSMSHandler.sendCoreSMS(sendCoreSMSDto);
            if (smsResultEx.isFailed()) {
                return ResultEx.fail("發送短信驗證碼失敗");//TODO 發送短信驗證碼失敗
            }
        } else {
            log.error("未開啟校驗短信驗證碼，請配置");
        }

        //核心客户号存入缓存
        otpValidator.setSignOtpCache(bo, coreClientNo, engName, chnName, otpCode);
        log.info("短信内容存入缓存：{}", otpCode);

        return ResultEx.ok();
    }

    /**
     * 签约
     */
    public ResultEx<SignVo> sign(SignBo bo) {
        if (!CustTypeEnum.P.getValue().equals(bo.getCustType().getValue())) {
            return ResultEx.fail("暫不支持非個人客戶！");//TODO 暫不支持非個人客戶
        }

        if(qpSignSerialService.existed(bo.getCustomerCode(), bo.getSignSerialNo())) {
            return ResultEx.fail("簽約流水號不可重複");//TODO
        }
        //1、短信驗證碼驗證 证件号，证件类型，手机号+账号：（驗證碼，核心客户号）  （失敗3次需重新發送）
        ResultEx<SignOtpBean> checkOtpResultEx = otpValidator.checkSignOtp(bo);
        if (checkOtpResultEx.isFailed()) {
            return ResultEx.makeResult(checkOtpResultEx.getRetCode(), checkOtpResultEx.getRetMsg());
        }

        SignOtpBean cacheSignOtpBean = checkOtpResultEx.getData();

        Product productInfo = productService.getByCode(ProductCodeEnum.EP_QP.getValue());
        if (ObjectUtil.isEmpty(productInfo)) {
            return ResultEx.fail("系统异常 产品未配置");//TODO 系统异常 产品未配置
        }
        //获取客户名称
        CustBaseInfo custBaseInfo = custBaseInfoService.getByCustomerCode(bo.getCustomerCode());
        if (ObjectUtil.isEmpty(custBaseInfo)) {
            return ResultEx.fail("客户不存在 客户数据未配置");//TODO 客户不存在 客户数据未配置
        }

        LocalDateTime now = LocalDateTime.now();

        //创建签约流水号
        String bankSignSerialNo = NoGenUtil.genSignSerialNo();
        //创建签约号
        String signNo = NoGenUtil.genSignNo();

        //2、生成簽約流水號，待驗證狀態
        QpSignSerial qpSignSerial = new QpSignSerial();
        qpSignSerial.setCustomerCode(bo.getCustomerCode());
        qpSignSerial.setCustomerName(custBaseInfo.getName());
        qpSignSerial.setMerchantOrderNo(bo.getSignSerialNo());
        qpSignSerial.setInnerOrderNo(bankSignSerialNo);
        qpSignSerial.setType(QpSignSerialTypeEnum.SIGN.getValue());
        //缓存中获取核心客户号
        qpSignSerial.setCoreClientNo(cacheSignOtpBean.getCoreClientNo());
        qpSignSerial.setCertType(bo.getCertType());
        qpSignSerial.setCertNo(bo.getCertNo());
        qpSignSerial.setCardType(BankAccTypeEnum.CURRENT.getValue());
        qpSignSerial.setBankAccNo(bo.getBankCardNo());
        qpSignSerial.setBankAccCname(bo.getBankAccountNameC());
        qpSignSerial.setBankAccEname(bo.getBankAccountNameE());
        qpSignSerial.setBirthDate(bo.getBirthDate());
        qpSignSerial.setCvv2(bo.getCvv2());
        qpSignSerial.setValidDate(bo.getValidDate());
        qpSignSerial.setPhoneArea(bo.getPhoneArea());
        qpSignSerial.setPhoneNo(bo.getPhoneNo());
        qpSignSerial.setSignNo(signNo);
        qpSignSerial.setStatus(QpSignSerialStatusEnum.SUCCESS.getValue());
        qpSignSerial.setCreateTime(now);


        //3、生成簽約信息
        QpSign existQpSign = qpSignService.get(bo.getCustomerCode(), bo.getBankCardNo());
        QpSign qpSign = new QpSign();
        if (ObjectUtil.isNotEmpty(existQpSign)) {
            qpSign.setId(existQpSign.getId());
        }
        qpSign.setCustomerCode(bo.getCustomerCode());
        qpSign.setCustomerName(custBaseInfo.getName());
        //qpSign.setCustomerUserId();
        qpSign.setCoreClientNo(cacheSignOtpBean.getCoreClientNo());
        qpSign.setCardType(BankAccTypeEnum.CURRENT.getValue());
        qpSign.setBankAccNo(bo.getBankCardNo());
        qpSign.setCertType(bo.getCertType());
        qpSign.setCertNo(bo.getCertNo());
        qpSign.setBankAccCname(bo.getBankAccountNameC());
        qpSign.setBankAccEname(bo.getBankAccountNameE());
        qpSign.setBirthDate(bo.getBirthDate());
        qpSign.setCvv2(bo.getCvv2());
        qpSign.setValidDate(bo.getValidDate());
        qpSign.setPhoneArea(bo.getPhoneArea());
        qpSign.setPhoneNo(bo.getPhoneNo());
        qpSign.setSignNo(signNo);
        qpSign.setStatus(QpSignStatusEnum.SIGNED.getValue());
        qpSign.setCreateTime(now);
        qpSign.setUpdateTime(now);
        qpSign.setCcy(CcyTypeEnum.MOP.getValue());

        SignBizBo signBizBo = new SignBizBo();
        signBizBo.setQpSignSerial(qpSignSerial);
        signBizBo.setQpSign(qpSign);
        //6、 如果没有个人用户开通状态记录，增加个人用户快捷开通状态为已开通
        QpUserOpen existQpUserOpen = qpUserOpenService.get(bo.getCustomerCode(), ProductCodeEnum.EP_QP.getValue(), bo.getBankCardNo());
        if (ObjectUtil.isEmpty(existQpUserOpen)) {
            //不存在，增加个人用户开通状态
            QpUserOpen qpUserOpen = new QpUserOpen();
            qpUserOpen.setProdCode(productInfo.getProdCode());
            qpUserOpen.setProdName(productInfo.getProdName());
            qpUserOpen.setCoreClientNo(cacheSignOtpBean.getCoreClientNo());
            qpUserOpen.setCustomerCode(bo.getCustomerCode());
            qpUserOpen.setCustomerName(custBaseInfo.getName());
            qpUserOpen.setCardType(BankAccTypeEnum.CURRENT.getValue());
            qpUserOpen.setBankAccNo(bo.getBankCardNo());
            qpUserOpen.setCertType(bo.getCertType());
            qpUserOpen.setCertNo(bo.getCertNo());
            qpUserOpen.setBankAccEname(bo.getBankAccountNameE());
            qpUserOpen.setBankAccCname(bo.getBankAccountNameC());
            qpUserOpen.setBirthDate(bo.getBirthDate());
            qpUserOpen.setCvv2(bo.getCvv2());
            qpUserOpen.setValidDate(bo.getValidDate());
            qpUserOpen.setPhoneArea(bo.getPhoneArea());
            qpUserOpen.setPhoneNo(bo.getPhoneNo());
            qpUserOpen.setStatus(QpUserOpenStatusEnum.OPENED.getValue());
            qpUserOpen.setRemark("自動開通");

            //5、設置用戶限額限次策略  每日限额，限次  每笔限额
            // 限额类型确定  單日限額只是針對客戶 單筆限額是針對渠道
            //获取全行默认限额限次 MOP寫定
            EpQuotaLimit quotaGlobalConfig = epQuotaLimitService.getGlobalQuotaLimitConfig(QuotaLimitTypeEnum.QUOTA, CcyTypeEnum.MOP);
            EpQuotaLimit timesGlobalConfig = epQuotaLimitService.getGlobalTimesLimitConfig(QuotaLimitTypeEnum.TIMES);
            if (ObjectUtil.isAnyEmpty(quotaGlobalConfig, timesGlobalConfig)) {
                return ResultEx.fail("全行默認限額为空");
            }

            //查詢是否已有限額信息，如果有則直接修改狀態為正常
            EpQuotaLimit existUserQpQuotaLimit = epQuotaLimitService.getUserQpQuotaLimit(cacheSignOtpBean.getCoreClientNo(), bo.getBankCardNo(), QuotaLimitTypeEnum.QUOTA, CcyTypeEnum.MOP);
            EpQuotaLimit existUserQpTimesLimit = epQuotaLimitService.getUserQpQuotaLimit(cacheSignOtpBean.getCoreClientNo(), bo.getBankCardNo(), QuotaLimitTypeEnum.TIMES, null);

            EpQuotaLimit epUserQuotaLimit = new EpQuotaLimit();
            if (ObjectUtil.isNotEmpty(existUserQpQuotaLimit)) {
                epUserQuotaLimit.setId(existUserQpQuotaLimit.getId());
                epUserQuotaLimit.setSingleLimit(quotaGlobalConfig.getSingleLimit());
                epUserQuotaLimit.setDayLimit(quotaGlobalConfig.getDayLimit());
                epUserQuotaLimit.setMonthLimit(quotaGlobalConfig.getMonthLimit());
                epUserQuotaLimit.setYearLimit(quotaGlobalConfig.getYearLimit());
            } else {
                epUserQuotaLimit.setSingleLimit(quotaGlobalConfig.getSingleLimit());
                epUserQuotaLimit.setDayLimit(quotaGlobalConfig.getDayLimit());
                epUserQuotaLimit.setMonthLimit(quotaGlobalConfig.getMonthLimit());
                epUserQuotaLimit.setYearLimit(quotaGlobalConfig.getYearLimit());
            }
            epUserQuotaLimit.setProdCode(productInfo.getProdCode());
            epUserQuotaLimit.setProdName(productInfo.getProdName());
            epUserQuotaLimit.setCustomerCode(custBaseInfo.getCustomerCode());
            epUserQuotaLimit.setCustomerName(custBaseInfo.getName());
            epUserQuotaLimit.setCoreClientNo(cacheSignOtpBean.getCoreClientNo());
            epUserQuotaLimit.setCoreAccNo(bo.getBankCardNo());
            epUserQuotaLimit.setStatus(QuotaLimitStatusEnum.NORMAL.getValue());
            epUserQuotaLimit.setQuotaType(QuotaUserTypeEnum.USER.getValue());
            epUserQuotaLimit.setType(QuotaLimitTypeEnum.QUOTA.getValue());
            epUserQuotaLimit.setCcy(CcyTypeEnum.MOP.getValue());
            epUserQuotaLimit.setEffTime(now);
            epUserQuotaLimit.setExpTime(now.plusYears(ePayOpenProperties.getQuotaLimitEffTime()));

            EpQuotaLimit epUserTimesLimit = new EpQuotaLimit();
            if (ObjectUtil.isNotEmpty(existUserQpTimesLimit)) {
                epUserTimesLimit.setId(existUserQpTimesLimit.getId());
                epUserTimesLimit.setSingleLimit(timesGlobalConfig.getSingleLimit());
                epUserTimesLimit.setDayLimit(timesGlobalConfig.getDayLimit());
                epUserTimesLimit.setMonthLimit(timesGlobalConfig.getMonthLimit());
                epUserTimesLimit.setYearLimit(timesGlobalConfig.getYearLimit());
            } else {
                epUserTimesLimit.setSingleLimit(timesGlobalConfig.getSingleLimit());
                epUserTimesLimit.setDayLimit(timesGlobalConfig.getDayLimit());
                epUserTimesLimit.setMonthLimit(timesGlobalConfig.getMonthLimit());
                epUserTimesLimit.setYearLimit(timesGlobalConfig.getYearLimit());
            }
            epUserTimesLimit.setProdCode(productInfo.getProdCode());
            epUserTimesLimit.setProdName(productInfo.getProdName());
            epUserTimesLimit.setCustomerCode(custBaseInfo.getCustomerCode());
            epUserTimesLimit.setCustomerName(custBaseInfo.getName());
            epUserTimesLimit.setCoreClientNo(cacheSignOtpBean.getCoreClientNo());
            epUserTimesLimit.setCoreAccNo(bo.getBankCardNo());
            epUserTimesLimit.setStatus(QuotaLimitStatusEnum.NORMAL.getValue());
            epUserTimesLimit.setQuotaType(QuotaUserTypeEnum.USER.getValue());
            epUserTimesLimit.setType(QuotaLimitTypeEnum.TIMES.getValue());
            epUserTimesLimit.setEffTime(now);
            epUserTimesLimit.setExpTime(now.plusYears(ePayOpenProperties.getQuotaLimitEffTime()));

            signBizBo.setQpUserOpen(qpUserOpen);
            signBizBo.setEpQuotaLimit(epUserQuotaLimit);
            signBizBo.setEpTimesLimit(epUserTimesLimit);
        }

        ResultEx signResultEx = signBizService.sign(signBizBo);
        if (signResultEx.isFailed()) {
            return ResultEx.fail("系統異常，未知錯誤！");//TODO 系統異常，未知錯誤！
        }
        String accountNo = StrUtil.sub(bo.getBankCardNo(), bo.getBankCardNo().length() - 4, bo.getBankCardNo().length());
        if (ObjectUtil.isEmpty(existQpUserOpen)) {
            SendCoreSMSDto sendCoreSMSDto = new SendCoreSMSDto();
            sendCoreSMSDto.setSmsTemplateId(CoreConfig.SMS_TEMPLATE_NOTIFY);
            sendCoreSMSDto.setTransactionType(SMSEnum.TRANS_TYPE_TEMPLATE.getValue());
            sendCoreSMSDto.setTransactionName(CoreConfig.TRANS_NAME_OPEN);
            sendCoreSMSDto.setSendType(SMSEnum.SEND_TYPE_SMS.getValue());
            sendCoreSMSDto.setSmsAccountNo(accountNo);
            sendCoreSMSDto.setPhoneNo(bo.getPhoneArea() + bo.getPhoneNo());
            sendCoreSMSDto.setDate(DateTimeUtil.convert2Str(now, ePayOpenProperties.getSmsDatePatter()));
            sendCoreSMSDto.setTime(DateTimeUtil.convert2Str(now, ePayOpenProperties.getSmsTimePatter()));
            sendCoreSMSDto.setMessageLength("480");
            sendCoreSMSDto.setFiller(" ");
            sendCoreSMSDto.setSendDate("00000000");
            sendCoreSMSDto.setSendTime("000000");

            ResultEx smsResultEx = coreSMSHandler.sendCoreSMS(sendCoreSMSDto);
            if (smsResultEx.isFailed()) {
                log.error("發送開通短信通知失敗");
            }
        }
        SendCoreSMSDto sendCoreSMSDto = new SendCoreSMSDto();
        sendCoreSMSDto.setSmsTemplateId(CoreConfig.SMS_TEMPLATE_NOTIFY);
        sendCoreSMSDto.setTransactionType(SMSEnum.TRANS_TYPE_TEMPLATE.getValue());
        sendCoreSMSDto.setTransactionName(CoreConfig.TRANS_NAME_SIGNED);
        sendCoreSMSDto.setSendType(SMSEnum.SEND_TYPE_SMS.getValue());
        sendCoreSMSDto.setSmsAccountNo(accountNo);
        sendCoreSMSDto.setPhoneNo(bo.getPhoneArea() + bo.getPhoneNo());
        sendCoreSMSDto.setDate(DateTimeUtil.convert2Str(now, ePayOpenProperties.getSmsDatePatter()));
        sendCoreSMSDto.setTime(DateTimeUtil.convert2Str(now, ePayOpenProperties.getSmsTimePatter()));
        sendCoreSMSDto.setMessageLength("480");
        sendCoreSMSDto.setFiller(" ");
        sendCoreSMSDto.setSendDate("00000000");
        sendCoreSMSDto.setSendTime("000000");

        ResultEx smsResultEx = coreSMSHandler.sendCoreSMS(sendCoreSMSDto);
        if (smsResultEx.isFailed()) {
            log.error("發送簽約短信通知失敗");
        }

        //7、返回簽約號
        SignVo signVo = new SignVo();
        signVo.setBankCardNo(bo.getBankCardNo());
        signVo.setBankSignNo(signNo);
        signVo.setBankSignTime(qpSign.getUpdateTime().format(DateTimeFormatter.ofPattern(DatePattern.PURE_DATETIME_PATTERN)));
        signVo.setBankSignSerialNo(bankSignSerialNo);
        signVo.setSignSerialNo(bo.getSignSerialNo());
        signVo.setAcCcy(bo.getCurrency());
        return ResultEx.ok(signVo);
    }

    /**
     * 解约
     */
    public ResultEx<UnsignVo> unSign(UnsignBo bo) {
        if(qpSignSerialService.existed(bo.getCustomerCode(), bo.getSignSerialNo())) {
            return ResultEx.fail("解約流水號不可重複");//TODO
        }
        //0 查詢當前簽約狀態
        QpSign existQpSign = qpSignService.getBySignNo(bo.getCustomerCode(), bo.getBankSignNo());
        if (ObjectUtil.isEmpty(existQpSign)) {
            return ResultEx.makeDataNotExistsResult("簽約信息不存在");//TODO 记录不存在
        }

        if (!QpSignStatusEnum.SIGNED.getValue().equals(existQpSign.getStatus())) {
            return ResultEx.fail("不是已簽約狀態，無法解約");//TODO 不是簽約狀態，無法解約
        }

        //获取客户名称
        CustBaseInfo custBaseInfo = custBaseInfoService.getByCustomerCode(bo.getCustomerCode());
        if (ObjectUtil.isEmpty(custBaseInfo)) {
            return ResultEx.fail("客戶不存在，客戶數據未配置！");//TODO 客戶不存在，客戶數據未配置！
        }

        LocalDateTime now = LocalDateTime.now();
        //1、生成解約流水
        //创建签约流水号
        String bankSignSerialNo = NoGenUtil.genSignSerialNo();

        QpSignSerial qpSignSerial = new QpSignSerial();
        qpSignSerial.setCustomerCode(bo.getCustomerCode());
        qpSignSerial.setCustomerName(custBaseInfo.getName());
        qpSignSerial.setMerchantOrderNo(bo.getSignSerialNo());
        qpSignSerial.setInnerOrderNo(bankSignSerialNo);
        qpSignSerial.setType(QpSignSerialTypeEnum.UNSIGN.getValue());
        //缓存中获取核心客户号
        qpSignSerial.setCoreClientNo(existQpSign.getCoreClientNo());
        qpSignSerial.setCertType(existQpSign.getCertType());
        qpSignSerial.setCertNo(existQpSign.getCertNo());
        qpSignSerial.setCardType(existQpSign.getCardType());
        qpSignSerial.setBankAccNo(existQpSign.getBankAccNo());
        qpSignSerial.setBankAccCname(existQpSign.getBankAccCname());
        qpSignSerial.setBankAccEname(existQpSign.getBankAccEname());
        qpSignSerial.setBirthDate(existQpSign.getBirthDate());
        qpSignSerial.setCvv2(existQpSign.getCvv2());
        qpSignSerial.setValidDate(existQpSign.getValidDate());
        qpSignSerial.setPhoneArea(existQpSign.getPhoneArea());
        qpSignSerial.setPhoneNo(existQpSign.getPhoneNo());
        qpSignSerial.setSignNo(bo.getBankSignNo());
        qpSignSerial.setStatus(QpSignSerialStatusEnum.SUCCESS.getValue());
        qpSignSerial.setCreateTime(now);
        qpSignSerial.setCcy(CcyTypeEnum.MOP.getValue());

        //2、設置簽約信息為解約狀態
        QpSign updateQpSign = new QpSign();
        updateQpSign.setId(existQpSign.getId());
        updateQpSign.setStatus(QpSignStatusEnum.CANCELED.getValue());

        UnsignBizBo bizBo = new UnsignBizBo();
        bizBo.setQpSignSerial(qpSignSerial);
        bizBo.setQpSign(updateQpSign);

        ResultEx unSignResultEx = signBizService.unsign(bizBo);
        if (unSignResultEx.isFailed()) {
            return unSignResultEx; //TODO 系統異常，未知錯誤！
        }
        String bankAccountNo = existQpSign.getBankAccNo();
        String accountNo = StrUtil.sub(bankAccountNo, bankAccountNo.length() - 4, bankAccountNo.length());
        SendCoreSMSDto sendCoreSMSDto = new SendCoreSMSDto();
        sendCoreSMSDto.setSmsTemplateId(CoreConfig.SMS_TEMPLATE_NOTIFY);
        sendCoreSMSDto.setTransactionType(SMSEnum.TRANS_TYPE_TEMPLATE.getValue());
        sendCoreSMSDto.setTransactionName(CoreConfig.TRANS_NAME_UNSIGN);
        sendCoreSMSDto.setSendType(SMSEnum.SEND_TYPE_SMS.getValue());
        sendCoreSMSDto.setSmsAccountNo(accountNo);
        sendCoreSMSDto.setPhoneNo(existQpSign.getPhoneArea() + existQpSign.getPhoneNo());
        sendCoreSMSDto.setDate(DateTimeUtil.convert2Str(now, ePayOpenProperties.getSmsDatePatter()));
        sendCoreSMSDto.setTime(DateTimeUtil.convert2Str(now, ePayOpenProperties.getSmsTimePatter()));
        sendCoreSMSDto.setMessageLength("480");
        sendCoreSMSDto.setFiller(" ");
        sendCoreSMSDto.setSendDate("00000000");
        sendCoreSMSDto.setSendTime("000000");

        ResultEx smsResultEx = coreSMSHandler.sendCoreSMS(sendCoreSMSDto);
        if (smsResultEx.isFailed()) {
            log.error("發送簽約成功短信通知失敗");
        }

        UnsignVo unsignVo = new UnsignVo();
        unsignVo.setBankUnSignTime(now.format(DateTimeFormatter.ofPattern(DatePattern.PURE_DATETIME_PATTERN)));
        unsignVo.setBankSignSerialNo(bankSignSerialNo);
        unsignVo.setSignSerialNo(bo.getSignSerialNo());
        return ResultEx.ok(unsignVo);
    }
}
